#include "videoplayer.h"
#include <QtDebug>
#include <thread>

#define AUDIO_MAX_PKT_SIZE 1000
#define VIDEO_MAX_PKT_SIZE 500

VideoPlayer::VideoPlayer(QObject *parent) : QObject(parent),m_TaskState(Stopped),m_seekTime(-1),m_aTime(0),m_volume(-1)
{
    m_mute = false;
    m_volume = 50;
    m_speedPlayRate = 2.0;
    if(SDL_Init(SDL_INIT_AUDIO)){
        qDebug() << "SDL_Init eror" << SDL_GetError();
        emit playFailed(this);
        return;
    }
    //connect()
}

void VideoPlayer::onVolumeChanged(int value){
    m_volume = value;
}

void VideoPlayer::onSpeedPlay(double rate){
    m_speedPlayRate = rate;
}

VideoPlayer::~VideoPlayer(){
    disconnect();
    stop();
    SDL_Quit();
}

void VideoPlayer::play(){
    //如果已经处于播放状态，则忽略
    if(this->m_TaskState == Playing) return;

    if(this->m_TaskState == Stopped){
        //要启动一个线程，开启播放
        std::thread([this](){
            readFile();
        }).detach();
    }else{
        setState(Playing);
    }
}

void VideoPlayer::stop(){
    //如果已经处于播放状态，则忽略
    if(this->m_TaskState == Stopped) return;
    setState(Stopped);
    //TODO
    free();

}

void VideoPlayer::pause(){
    if(this->m_TaskState != Playing) return;
    setState(Paused);
}

void VideoPlayer::setState(State state){
    //如果状态没有被改变
    if(this->m_TaskState == state) return;
    this->m_TaskState = state;
    emit stateChanged(this);
}

bool VideoPlayer::isPlaying(){
    return m_TaskState == Playing;
}

VideoPlayer::State VideoPlayer::getState(){
    return m_TaskState;
}

void VideoPlayer::setFileName(const QString& fileName){
    this->m_FileName = fileName;
}


QString VideoPlayer::getFileName(){
    return this->m_FileName;
}

int VideoPlayer::getDuration(){
    //#define AV_TIME_BASE_Q          (AVRational){1, AV_TIME_BASE}
    //AV_TIME_BASE = 1000000
    //实际计算是把微秒转成秒
    //m_fmtCtx->duration 表示的是微秒
    //av_q2d(AV_TIME_BASE_Q) = 1/AV_BASE_TIME
    return m_fmtCtx ? round(m_fmtCtx->duration * av_q2d(AV_TIME_BASE_Q)):0;
}

int VideoPlayer::getTime(){
    return round(m_aTime);
}

void VideoPlayer::setTime(int seekTime){
    m_seekTime = seekTime;
}

void VideoPlayer::setVolumn(int volume){
    m_volume = volume;
}

int VideoPlayer::getVolumn(){
    return m_volume;
}

void VideoPlayer::setMute(bool mute){
    m_mute = mute;
}

bool VideoPlayer::isMute(){
    return m_mute;
}

int VideoPlayer::initDecoder(AVCodecContext** decodeCtx,AVStream** stream,AVMediaType type){
    int ret = av_find_best_stream(m_fmtCtx,type,-1,-1,nullptr,0);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "initDecoder error" << errbuf;
        return ret;
    }

    //检验流
    int streamIdx = ret;
    *stream = m_fmtCtx->streams[streamIdx];
    if(!*stream){
        qDebug() << "stream is empty";
        return -1;
    }

    //为当前流找到合适的解码器
    const AVCodec* decoder = avcodec_find_decoder((*stream)->codecpar->codec_id);
    if(!decoder){
        qDebug() << "decoder not found" << (*stream)->codecpar->codec_id;
        return -1;
    }

    //初始化解码上下文
    *decodeCtx = avcodec_alloc_context3(decoder);
    if(!decodeCtx){
        qDebug() << "avcodec_alloc_context3 error";
        return -1;
    }

    //从流中拷贝参数到解码上下文中
    ret = avcodec_parameters_to_context(*decodeCtx,(*stream)->codecpar);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "avcodec_parameters_to_context error" << errbuf;
        return ret;
    }

    //打开解码器
    ret = avcodec_open2(*decodeCtx,decoder,nullptr);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "avcodec_open2 error" << errbuf;
        return ret;
    }

    return 0;
}

void VideoPlayer::readFile(){
    //avformat_open_input
    //avformat_find_stream_info
    //initAudioInfo
    //initVideoInfo
    int ret = 0;
    //创建封装上下文，打开文件
    ret = avformat_open_input(&m_fmtCtx,m_FileName.toUtf8().data(),nullptr,nullptr);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "avformat_open_input error" << errbuf;
        return;
    }

    //检索流信息
    ret = avformat_find_stream_info(m_fmtCtx,nullptr);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "avformat_find_stream_info error" << errbuf;
        return;
    }

    //初始化视频信息
    m_bHasVideo = initVideoInfo() >= 0;
    //初始化音频信息
    m_bHasAudio = initAudioInfo() >= 0;

    if(!m_bHasAudio && !m_bHasVideo){
        emit playFailed(this);
        free();
        return;
    }

    //初始化完毕
    emit initFinished(this);

    //改变状态
    setState(Playing);

    //音频解码子线程
    SDL_PauseAudio(0);

    //开启新的线程去解码视频数据
    std::thread([this](){
        decodeVideo();
    }).detach();

    AVPacket pkt;
    while(m_TaskState != Stopped){
        //处理seek操作
        if(m_seekTime >= 0){
            int nStreamIdx;
            if(m_bHasAudio){
                nStreamIdx = m_aStream->index;
            }else{
                nStreamIdx = m_vStream->index;
            }

            AVRational timeBase = m_fmtCtx->streams[nStreamIdx]->time_base;
            int64_t ts = m_seekTime / av_q2d(timeBase);

            ret = avformat_seek_file(m_fmtCtx,nStreamIdx,INT64_MIN,ts,INT64_MAX,0);
            if(ret < 0){
                qDebug() << "seek失败" << m_seekTime << ts << nStreamIdx;
                m_seekTime = -1;
            }else{
                qDebug() << "seek成功" << m_seekTime << ts << nStreamIdx;
                // 清空之前读取的数据包
                clearAudioPktList();
                clearVideoPktList();
                m_vSeekTime = m_seekTime;
                m_aSeekTime = m_seekTime;
                m_seekTime = -1;
                // 恢复时钟
                m_aTime = 0;
                m_vTime = 0;
            }
        }
        int vSize = m_vPktList.size();
        int aSize = m_aPktList.size();

        if(vSize >= VIDEO_MAX_PKT_SIZE || aSize >= AUDIO_MAX_PKT_SIZE){
            SDL_Delay(1);
            continue;
        }

        ret = av_read_frame(m_fmtCtx,&pkt);
        if(ret == 0){
            if(pkt.stream_index == m_aStream->index){
                addAudioPkt(pkt);
            }else if(pkt.stream_index == m_vStream->index){
                addVideoPkt(pkt);
            }else{
                av_packet_unref(&pkt);
            }
        }else if(ret == AVERROR_EOF){
            if(vSize == 0 && aSize == 0){
                m_fmtCtxCanFree = true;
                break;
            }
        }else{
            char errbuf[1024];
            av_strerror(ret, errbuf, sizeof (errbuf));
            qDebug() << "av_read_frame error" << errbuf;
            continue;
        }
    }
    if(m_fmtCtxCanFree){
        //文件正常播放完毕
        stop();
    }else{
        m_fmtCtxCanFree = true;
    }
}


void VideoPlayer::free(){
    //这种等待的方法对吗? TODO
    while(m_bHasAudio && !m_aCanFree);
    while(m_bHasVideo && !m_vCanFree);
    while(!m_fmtCtxCanFree);
    avformat_close_input(&m_fmtCtx);
    m_fmtCtxCanFree = false;
    m_seekTime = -1;
    freeAudio();
    freeVideo();
}

void VideoPlayer::freeVideo(){
    clearVideoPktList();
    avcodec_free_context(&m_vDecodeCtx);
    av_frame_free(&m_vSwsInFrame);
    if (m_vSwsOutFrame) {
        av_freep(&m_vSwsOutFrame->data[0]);
        av_frame_free(&m_vSwsOutFrame);
    }
    sws_freeContext(m_vSwsCtx);
    m_vSwsCtx = nullptr;
    m_vStream = nullptr;
    m_vTime = 0;
    m_vCanFree = false;
    m_vSeekTime = -1;
}

void VideoPlayer::clearVideoPktList(){
    m_vMutex.lock();
    for(AVPacket &pkt : m_vPktList){
        av_packet_unref(&pkt);
    }
    m_vPktList.clear();
    m_vMutex.unlock();
}
